﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MediaInfoModelNS;
using AvsBuilderModelNS;
using MencoderModelNS;
using AudioCoderModelNS;
using Mp4BoxModelNS;

namespace CoderModelNS
{
    class CoderModel
    {
        public delegate void OutputHandler(string outStr);
        public event OutputHandler outputHandler;
        
        private string homeDirectory;
        private string inputMediaFile;
        private string outputMediaFile;

        private static int[] resolutionSet = { 0, 1080, 720, 480, 360, 240}; 
        

        AvsBuilderModel avsBuilder;
        public AvsBuilderModel AvsBuilder
        {
            get { return avsBuilder; } 
        }

        AudioCoderModel audioCoder;
        public AudioCoderModel AudioCoder
        {
            get { return audioCoder; }
        }
        
        
        MencoderModel videoCoder;
        public MencoderModel VideoCoder
        {
            get { return videoCoder; }
        }
        
        Mp4BoxModel mp4Muxer;
        public Mp4BoxModel Mp4Muxer
        {
            get { return mp4Muxer; }
        }

        private MediaInfoModel audioInfo;

        public MediaInfoModel AudioInfo
        {
            get { return audioInfo; }
        }
        private MediaInfoModel videoInfo;

        public MediaInfoModel VideoInfo
        {
            get { return videoInfo; }
        }


        public CoderModel(string homeDir, string inputFile, string outputFile) {
            homeDirectory = homeDir;
            inputMediaFile = inputFile;
            outputMediaFile = outputFile;
        }


        public void initCoderModel(string videoCrf, string audioBitRate, int method, int resolution) {
            string mediaInfoPath = homeDirectory + @"tools\MediaInfo\MediaInfo.exe";
            
            audioInfo = new MediaInfoModel(mediaInfoPath, inputMediaFile, "Audio");
            audioInfo.outputHandler += new MediaInfoModel.OutputHandler(outputHandler);
            
            audioInfo.addParameter("SamplingRate");
            audioInfo.updateInfo();


            videoInfo = new MediaInfoModel(mediaInfoPath, inputMediaFile, "Video");
            videoInfo.outputHandler += new MediaInfoModel.OutputHandler(outputHandler);
            
            videoInfo.addParameter("FrameRate");
            videoInfo.addParameter("Standard");
            videoInfo.addParameter("Width");
            videoInfo.addParameter("Height");
            videoInfo.addParameter(@"DisplayAspectRatio/String");
            //videoInfo.addParameter(@"PixelAspectRatio/String");
            videoInfo.updateInfo();

            initAvsBuilder();
            addVideoFilterToAVS(resolution);
            avsBuilder.creatAvsFiles();
            
            initVideoCoderModel(videoCrf,method);
            initAudioCoderModel(audioBitRate);
            initMp4Muxer(resolution);
        }

        private void addVideoFilterToAVS(int resolution) {
            if (resolution == 0) { return; }
            string standard = videoInfo.getParameter("Standard");
            string dar = videoInfo.getParameter(@"DisplayAspectRatio/String");
            int width = Convert.ToInt32(videoInfo.getParameter("Width"));
            int height = Convert.ToInt32(videoInfo.getParameter("Height"));
            int destHight = resolutionSet[resolution];
            
            if (standard.ToUpper().Equals("NTSC") ||standard.ToUpper().Equals("PAL")) { 
                if (width == 720) {
                    avsBuilder.addCrop(8,0,704,height);
                }
                width = 704;
            }
            if (height == 1088) {
                avsBuilder.addCrop(0, 4, width, 1080);
                height = 1080;
            }
            if (dar.Equals("4:3"))
            {
                avsBuilder.addResize(destHight * 4 / 3, destHight);
                return;
            }
            if (dar.Equals("16:9"))
            {
                avsBuilder.addResize(destHight * 16 / 9, destHight);
                return;
            }
            if (dar.Equals("5:4"))
            {
                avsBuilder.addResize(destHight * 5 / 4, destHight);
                return;
            }
            avsBuilder.addResize(destHight * width / height, destHight);


        }


        public void startCoding() {
            //avsBuilder.creatAvsFiles();
            videoCoder.startCoding();
            audioCoder.startCoding();
            mp4Muxer.startCoding();
            outputHandler("\n\n===================================\n");
            outputHandler("!!!!!Coding Completed!!!!");

        }

        public void initAvsBuilder() {
            avsBuilder = new AvsBuilderModel(inputMediaFile, homeDirectory);
            //avsBuilder.creatAvsFiles();
        }

        public void initVideoCoderModel(string videoCrf, int method) { 
            
            string avsVideoPath = homeDirectory + "video.avs";
            string outputVideoPath = homeDirectory + "video.h264";
            string mencoderPath = homeDirectory + @"tools\mencoder\mencoder.exe";
            videoCoder = new MencoderModel(avsVideoPath, outputVideoPath, mencoderPath);
            videoCoder.outputHandler += new MencoderModel.OutputHandler(outputHandler);
            videoCoder.creatArgs(videoCrf, method);
            //videoCoder.startCoding();
        }

        public void initAudioCoderModel(string audioBitRate) { 
            string waviPath = homeDirectory + @"tools\wavi\wavi.exe";
            string aacEncPath = homeDirectory + @"tools\enc_aacPlus\enc_aacPlus.exe";
            string outputAudioPath = homeDirectory + "audio.aac";
            string avsAudioPath = homeDirectory + "audio.avs";

            string audioSampleRate = audioInfo.getParameter("SamplingRate").Split(' ')[0];
            
            audioCoder = new AudioCoderModel(waviPath, aacEncPath, avsAudioPath, outputAudioPath);
            audioCoder.outputHandler += new AudioCoderModel.OutputHandler(outputHandler);
            audioCoder.buildArgs(audioBitRate, audioSampleRate);
            //audioCoder.startCoding();
        }

        public string getPAR() {
            
            string standard = videoInfo.getParameter("Standard");
            int width = Convert.ToInt32(videoInfo.getParameter("Width"));
            int height = Convert.ToInt32(videoInfo.getParameter("Height"));
            string dar = videoInfo.getParameter(@"DisplayAspectRatio/String");
            if (standard.ToUpper().Equals("NTSC")) {
                if (dar.Equals("4:3")) {
                    return "10:11";    
                }
                if (dar.Equals("16:9")) {
                    return "44:33";
                }
                return "1:1";
            }
            if (standard.ToUpper().Equals("PAL")) {
                if (dar.Equals("4:3"))
                {
                    return "12:11";
                }
                if (dar.Equals("16:9"))
                {
                    return "16:11";
                }
                return "1:1";
            }
            if (height == 1088) {
                height = 1080;
            }
            if (dar.Equals("16:9")) {
                if ( Math.Abs(16.0 * height / 9.0 / width - 1.0) < 0.05) {
                    return "1:1";
                }
                return String.Format("{0}:{1}", 16 * height, 9 * width);
            }
            if (dar.Equals("4:3"))
            {
                if (Math.Abs(4.0 * height / 3.0 / width - 1.0) < 0.05)
                {
                    return "1:1";
                }
                return String.Format("{0}:{1}", 4 * height, 3 * width);
            }
            if (dar.Equals("5:4"))
            {
                if (Math.Abs(5.0 * height / 4.0 / width - 1.0) < 0.05)
                {
                    return "1:1";
                }
                return String.Format("{0}:{1}", 5 * height, 4 * width);
            }
            return "1:1";
        }

        public void initMp4Muxer(int resolution)
        { 
            string mp4BoxPath = homeDirectory + @"tools\mp4box\mp4box.exe";
            string rawAudioPath = homeDirectory + "audio.aac";
            string rawVideoPath = homeDirectory + "video.h264";

            string fps = videoInfo.getParameter("FrameRate");
            
            mp4Muxer = new Mp4BoxModel(mp4BoxPath, rawVideoPath, rawAudioPath, outputMediaFile);
            mp4Muxer.outputHandler += new Mp4BoxModel.OutputHandler(outputHandler);
            if (resolution == 0)
            {
                mp4Muxer.createArgs(fps, getPAR(), (audioCoder.AudioCodeType < 2));
            }
            else {
                mp4Muxer.createArgs(fps, "1:1", (audioCoder.AudioCodeType < 2));
            }

            
            //mp4Muxer.startCoding();
        }





    }
}
